using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using UnityEngine;

#region LLMInteractDefine
///前期尝试过互相包含 , 又尝试过钥匙对的Pairs类型, 后来考虑到复制的限制性要求, 添加了接口和抽象类
///最终使用默认接口和抽象虚属性来实现,有参考和限制, 扩展更加便捷自由
public class LLM_IPairs_HelloSample : LLMInteractPairsBase
{
    public override string prompt => "you will role play a Character,a nice pet ,case sensitivity, json format, ";
    public override string context => interactContext;
    public override IJsonable JsonableObject => new JsonPack();

    public class JsonPack : IJsonable
    {
        [JsonProperty]
        public string motion;
        [JsonProperty]
        public string words;
    }
}
/// <summary>
/// 该接口提示了PairsBase必须提供一个实现了IJsonable的类,来实现Json预限制
/// </summary>
public class IJsonable
{
    public string ToJson()
    {
        var sample = CreateSample();
        if (sample == null) sample = this;
        return JsonConvert.SerializeObject(sample);
    }
    public virtual IJsonable CreateSample() => null;

}
/// <summary>
/// LLM交互模板，自定义的交互行为必须从模板类派生
/// </summary>

public class LLMInteractPairsBase
{
    /// <summary>
    /// 这是一个简化Tag,用来综述交互
    /// </summary>
    public virtual string tag => "baseInteract";
    public virtual string prompt => "";
    // public string jsonHeader => JsonableObject != null ? "以json格式返回,输出严格按照下面给出的JsonClass:" : "";
    public string jsonHeader => JsonableObject != null ? "以json格式返回,输出参考该Json类:" : "";
    public string jsonBody => JsonableObject != null ? JsonableObject.ToJson() : "";
    public virtual string context => interactContext;
    public virtual string positiveSample => "";
    public virtual string negativeSample => "";
    public string name => this.GetType().Name;
    public IList paramList1;
    public string interactContext;
    public string response;
    public string sample => string.IsNullOrEmpty(positiveSample + negativeSample) ? "" : $"samples:{{positive:{positiveSample}, negative:{negativeSample},tips:请你只在格式上参考样例，在内容上必须重新思考}},\n";
    public virtual IJsonable JsonableObject => null;
    public string randomRole => $",本次生成随机数种子:{randomSeed},";
    public bool jsonManual = false;
    public int randomSeed
    {
        get
        {
            var r = new System.Random();
            return r.Next(int.MaxValue);
        }
    }
    public Action<string> onResponse;
    public string ToPrompt =>
        $"role:{{ {prompt} }},\n" +
        $"rule:{{ {jsonHeader + jsonBody + randomRole} }},\n" +
        sample +
        //$"history:{{empty,tips:你的回复同时需要根据历史输入评估}}\n"+
        $"curUserInput:{{ {context} }}"
        ;

    //还是需要符合编程逻辑
    //TODO: 这里得加一个json tag
    public virtual async Task<string> Generate()
    {
        VLLMGate.ModelSetting(JsonableObject != null || jsonManual);
        response = await VLLMGate.Generate(ToPrompt);
        if (!string.IsNullOrEmpty(response)) onResponse?.Invoke(response);
        return response;
    }
    public bool TryDeJson<T>(out T obj) where T : IJsonable
    {
        obj = default;
        if (response == null) return false;
        else
        {
            obj = JsonConvert.DeserializeObject<T>(response);
            return true;
        }
    }

}

public class LLMCharacterInteractPairBase : LLMInteractPairsBase
{
    public VLLMCharacter character; //自带参数信息,需要tostring方法外部拿出来
    public string ToCharacterPrompt => $"characterDescription:{character.characterDescription}" +
        // $"history:{character.GetCachedInteracts()}" +
        ToPrompt;
    public override async Task<string> Generate()
    {
        VLLMGate.ModelSetting(JsonableObject != null);
        response = await VLLMGate.Generate(ToCharacterPrompt);
        return response;
    }

}

#endregion

#region  CommonInteract
public class LLMIP_Simplify : LLMInteractPairsBase
{
    public override string prompt => "你是一个有记忆的虚拟对象，你将根据下面输入的内容作出简化后，存放到你的持久化记忆数据库中，请你将下面的内容精简提取为描述性词语";
    public override string positiveSample => "语言风格如：喜欢吃辣，在森林相遇，和主人共进了晚餐，情感很好";
}
public class LLMIP_Selector : LLMInteractPairsBase
{
    public override string prompt => "你是一个分类器，请根据用户的输入从下列函数中选择最匹配的一个,只返回函数名称不要推理过程:" + paramList1.ToLLMString();
    // public override string positiveSample => "可选{methodA,methodB,methodC} 返回methoA";
}

#endregion

public class LLMInteractLinkBase
{
    public virtual LLMInteractPairsBase Entry
    {
        get => _entry;
    }

    public virtual List<LLMInteractPairsBase> Selection
    {
        get => _selection;
    }
    protected LLMInteractPairsBase _entry;
    protected List<LLMInteractPairsBase> _selection;

    public async Task<LLMInteractPairsBase> Select(string context)
    {
        Entry.interactContext = context;
        var selectResult = await Entry.Generate();
        return NameToSelection(selectResult);
    }
    public async Task<string> Interact(string context)
    {
        var selectionResult = await Select(context);
        selectionResult.interactContext = context;
        return await selectionResult.Generate();
    }
    public LLMInteractPairsBase NameToSelection(string param)
    {
        for (int i = 0; i < Selection.Count; i++)
        {
            if (Selection[i].GetType().ToString() == param)
            {
                return Selection[i];
            }
        }
        throw new Exception($"LLM链交互中不包含返回Seletion:{param},请检测Prompt规范!");
    }
}

public class LLMIL_SelectionLinkSample : LLMInteractLinkBase
{
    public LLMIL_SelectionLinkSample()
    {
        _entry = new LLMIP_Selector();
        _selection = new List<LLMInteractPairsBase>()
        {
            new LLMIL1_餐厅场景_店面信息(),
            new LLMIL1_餐厅场景_询问菜品(),
        };
        _entry.paramList1 = _selection;
    }
}